package dbPhase.hypeerweb;

import java.util.ArrayList;

public abstract class BroadcastVisitor implements Visitor {

	/*The default constructor.
Pre-condition:
None
Post-condition:
TRUE
*/
	public BroadcastVisitor() {
		//TODO
	}

	/*	Creates the minimum set of parameters needed when invoking an accept method during a broadcast. At the top level (this level)
	 * there are no required parameters.If there are more required parameters in a subclass, this method is overridden.
	Pre-condition:
	None
	Post-condition:
	|result| = 0*/
	public static Parameters createInitialParameters() {
		Parameters p = new Parameters();
		p.set("Source", -1);
		return p;
	}


/*The visit operation called by a node in the accept method implementing the broadcast visitor pattern.
Specified by:
visit in interface Visitor
Parameters:
node - the node being visited
parameters - the parameters used during the broadcast.
Pre-condition:
node ≠ null AND parameters ≠ null
Post-condition:
parameters.containsKey(STARTED_KEY) ⇒
  operation(node, parameters).post-condition AND
  ∀ neighbor (neighbor ∈ node.neighbors AND neighbor has not and will not be visited by any other node ⇒
      neighbor.accept(this, parameters).post-condition)
ELSE
  parameters.containsKey(STARTED_KEY) AND
  ∃ node0 (node0 ∈ HyPeerWeb AND node0.webId = 0 AND node0.accept(this, parameters).post-condition)*/
	public void visit(Node node,Parameters parameters) {
		ArrayList<Node> targets = new ArrayList<Node>();

		//Do operation
		operation(node, parameters);

		// Get source, use that to find out who to send to
		if (parameters.get("Source") == null) {
			parameters.set("Source", -1);
		}


		int source = (Integer) parameters.get("Source");

		// Find all targets
		for (Node n : node.neighbors) {
			if (n.getWebIdValue() != source && n.getWebId().isLowerOnTree(node.webId)) {
				targets.add(n);
			}
		}

		// Send to all targets
		for (Node n : targets) {
			//Set source
			parameters.set("Source", node.getWebIdValue());
			n.accept(this, parameters);
		}
	}

/*The abstract operation to be performed on all nodes. This operation must be implemented in all concrete subclasses.
Parameters:
node - the node the operation is to be performed on.
parameters - the parameters needed to perform the operation.
Pre-condition:
node ≠ null AND parameters ≠ null
Post-condition:
TRUE*/

	protected abstract void operation(Node node, Parameters parameters);

    protected static final String STARTED_KEY = "started";
    protected static final WebId NODE_0_ID = new WebId(0);
}
